package com.wk.database.entity;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.wk.database.entity.definition.Column;
import com.wk.database.entity.definition.ColumnType;
import com.wk.database.entity.definition.Condition;

/**
 * 方法类：在数据库中更新实体类的某一实例
 * 
 * @author Bai Yu
 *
 * @param <Entity>
 */
@Deprecated
public class Update<Entity> {
	public Update(Class<Entity> entity) throws NoMappedIdentifierException, NoMappedFieldException {
		table = EntityAnalyzer.findTable(entity);
		fields = EntityAnalyzer.classifyMappedFields(entity);
	}

	/**
	 * 预览将会创建的SQL更新语句。无副作用<br>
	 * 更新语句形如"update table set field1 = ?, field2 = ? where pk1 = ? and pk2 = ?"
	 * <br>
	 * 其中，主键及被更新的列按相应字段在实体类中出现的顺序排列
	 * 
	 * @return SQL语句
	 */
	public String getSQL() {
		StringBuilder result = new StringBuilder();

		result.append("update " + table + " ");
		generateSetClause(result);
		result.append(" ");
		generateWhereClause(result);
		generateConditionClause(result);

		return result.toString();
	}

	/**
	 * 连接数据库<br>
	 * 如果连接成功，则可以任意次数地执行更新
	 * 
	 * @param connection
	 *            数据库连接
	 * @throws SQLException
	 *             连接失败
	 */
	public void connect(Connection connection) throws SQLException {
		statement = connection.prepareStatement(getSQL());
	}

	/**
	 * 执行更新
	 * 
	 * @param object
	 *            被更新的对象
	 * @return 数据库中被更新的行数
	 * @throws SQLException
	 *             更新失败
	 */
	public int execute(Entity object) throws SQLException, FieldUnaccessableException {
		int fieldIndex = 1;
		for (Field field : fields.mappedCommonFields) {
			String type = field.getAnnotation(Column.class).type();
			try {
				if (type.equals(ColumnType.STRING)) {
					statement.setString(fieldIndex, (String)field.get(object));
				} else if (type.equals(ColumnType.INT)) {
					statement.setInt(fieldIndex, (int)field.get(object));
				}
			} catch (IllegalArgumentException e) {
				throw new FieldUnaccessableException(object.getClass(), field, e);
			} catch (IllegalAccessException e) {
				throw new FieldUnaccessableException(object.getClass(), field, e);
			}
			
			fieldIndex++;
		}
		
		for (Field field : fields.mappedIdentifierFields) {
			String type = field.getAnnotation(Column.class).type();
			try {
				if (type.equals(ColumnType.STRING)) {
					statement.setString(fieldIndex, (String)field.get(object));
				} else if (type.equals(ColumnType.INT)) {
					statement.setInt(fieldIndex, (int)field.get(object));
				}
			} catch (IllegalArgumentException e) {
				throw new FieldUnaccessableException(object.getClass(), field, e);
			} catch (IllegalAccessException e) {
				throw new FieldUnaccessableException(object.getClass(), field, e);
			}
			
			fieldIndex++;
		}

		return statement.executeUpdate();
	}

	/* 根据普通字段生成set子句，形如“set field1 = ?, field2 = ?” */
	private void generateSetClause(StringBuilder result) {
		result.append("set ");

		boolean firstField = true;
		for (Field field : fields.mappedCommonFields) {
			if (firstField) {
				firstField = false;
				result.append(field.getAnnotation(Column.class).name() + " = ?");
			} else {
				result.append(", " + field.getAnnotation(Column.class).name() + " = ?");
			}
		}
	}

	/* 根据主键创建where子句，形如“where pk1 = ? and pk2 = ? and pk3 = ?” */
	private void generateWhereClause(StringBuilder result) {
		result.append("where ");

		boolean firstField = true;
		for (Field field : fields.mappedIdentifierFields) {
			if (firstField) {
				firstField = false;
				result.append(field.getAnnotation(Column.class).name() + " = ?");
			} else {
				result.append(" and " + field.getAnnotation(Column.class).name() + " = ?");
			}
		}
	}
	
	/* 创建where后的条件子句，形如"and column1 > 5 and column2 = 'completed'" */
	private void generateConditionClause(StringBuilder result){
		for (Field field : fields.mappedCommonFields) {
			Condition condition = field.getAnnotation(Condition.class);
			if (condition == null) {
				continue;
			}

			Column column = field.getAnnotation(Column.class);
			result.append(" and " + column.name() + " " + condition.value());
		}
	}

	private String table;
	private ClassifiedFields fields;

	private PreparedStatement statement;
}
